#pragma once

#include "Socket.hpp"
#include "TcpServer.hpp"
#include "Log.hpp"
#include "Util.hpp"
#include <iostream>
#include <string>
#include <memory>
#include <sstream>
#include <functional>
#include <unordered_map>

using namespace SocketModule;
using namespace LogModule;

const std::string gspace = " ";
const std::string glinespace = "\r\n";
const std::string glinesep = ": ";

const std::string webroot = "./wwwroot";
const std::string homepage = "index.html";
const std::string page_404 = "/404.html";

class HttpRequest
{
public:
    HttpRequest()
        :_is_interact(false)
    {}
    std::string Serialize()
    {
        return std::string();
    }
    void ParseReqLine(std::string &reqline)
    {
        std::stringstream ss(reqline);
        ss >> _method >> _uri >> _version;
    }
    bool Deserialize(std::string &reqstr)
    {
        std::string reqline;
        bool res = Util::ReadOneLine(reqstr, &reqline, glinespace);
        LOG(LogLevel::DEBUG) << reqline;
        
        ParseReqLine(reqline);

        if (!res)
        {
            LOG(LogLevel::FATAL) << "Deserialize fail";
            return false;
        }

        LOG(LogLevel::DEBUG) << "_method: " << _method;
        LOG(LogLevel::DEBUG) << "_uri: " << _uri;
        LOG(LogLevel::DEBUG) << "_version: " << _version;
        if (_uri == "/") // 自动进入首页
            _uri = webroot + _uri + homepage;
        else
            _uri = webroot + _uri;

        return true;
    }
    std::string Uri()
    {
        return _uri;
    }
    ~HttpRequest()
    {
    }
private:
    std::string _method; // 请求方法
    std::string _uri; // 路径
    std::string _version; // http版本

    std::unordered_map<std::string, std::string> _headers; // 请求报头
    std::string _blankline; // 换行符
    std::string _text; // 请求正文

    std::string _args;
    bool _is_interact;
};

class HttpResponse
{
public:
    HttpResponse() 
        :_blankline(glinespace)
        ,_version("HTTP/1.0")
    {
    }
    std::string Serialize()
    {
        std::string status_line = _version + gspace + std::to_string(_code) + gspace + _desc + glinespace;
        std::string resp_header;
        for (auto &header : _headers)
        {
            std::string line = header.first + glinesep + header.second + glinespace;
            resp_header += line;
        }

        return status_line + resp_header + _blankline + _text;
    }
    void SetTargetFile(const std::string &target)
    {
        _targetfile = target;
    }
    void SetCode(int code)
    {
        _code = code;
        switch (_code)
        {
        case 200:
            _desc = "OK";
            break;
        case 404:
            _desc = "Not Found";
            break;
        case 301:
            _desc = "Moved Permanently";
            break;
        case 302:
            _desc = "See Other";
            break;
        default:
            break;
        }
    }
    void SetHeader(const std::string &key, const std::string &value)
    {
        auto iter = _headers.find(key);
        if (iter != _headers.end())
            return;
        _headers.insert(std::make_pair(key, value));
    }
    std::string Uri2Suffix(const std::string &targetfile) // Conent-Type对照表
    {
        auto pos = targetfile.rfind(".");
        if (pos == std::string::npos)
        {
            return "text/html";
        }

        std::string suffix = targetfile.substr(pos);
        if (suffix == ".html" || suffix == ".htm")
            return "text/html";
        else if (suffix == ".jpg")
            return "image/jpeg";
        else if (suffix == "png")
            return "image/png";
        else
            return "";
    }
    bool MakeResponse()
    {
        if (_targetfile == "./wwwroot/favicon.ico")
        {
            LOG(LogLevel::DEBUG) << "用户请求: " << _targetfile << "忽略它";
            return false;
        }

        int filesize = 0;
        bool res = Util::ReadFileContent(_targetfile, &_text);
        if (!res)
        {
            _text = "";
            LOG(LogLevel::WARNING) << "client want get : " << _targetfile << " but not found";
            SetCode(404);
            _targetfile = webroot + page_404;
            filesize = Util::FileSize(_targetfile);
            Util::ReadFileContent(_targetfile, &_text);
            std::string suffix = Uri2Suffix(_targetfile);
            SetHeader("Conent-Type", suffix);
            SetHeader("Content-Length", std::to_string(filesize));
        }
        else
        {
            LOG(LogLevel::DEBUG) << "读取文件: " << _targetfile;
            SetCode(200);
            filesize = Util::FileSize(_targetfile);
            std::string suffix = Uri2Suffix(_targetfile);
            Util::ReadFileContent(_targetfile, &_text);
            SetHeader("Conent-Type", suffix);
            SetHeader("Content-Length", std::to_string(filesize));
        }
        return true;
    }
    bool Deserialize(std::string &reqstr)
    {
        return true;
    }
    ~HttpResponse()
    {
    }
// private:
public:
    std::string _version; // http版本
    int _code; // 状态码
    std::string _desc; // 状态码描述

    std::unordered_map<std::string, std::string> _headers; // 响应报头
    std::string _blankline; // 换行符
    std::string _text; // 响应正文

    // 其他属性
    std::string _targetfile;
};

class Http
{
public:
    Http(uint16_t port)
        :tsvrp(std::make_unique<TcpServer>(port))
    {
    }
    void HandlerHttpRquest(std::shared_ptr<Socket> &sock, InetAddr &client)
    {
        std::string httprestr;
        int n = sock->Recv(&httprestr);
        if (n > 0)
        {
            HttpRequest req;
            req.Deserialize(httprestr);

            HttpResponse resp;
            resp.SetTargetFile(req.Uri());
            resp.MakeResponse();
            std::string response_str = resp.Serialize();
            sock->Send(response_str);
        }
    }
    void Start()
    {
        tsvrp->Start([this](std::shared_ptr<Socket> &sock, InetAddr &client){ // 使用tsvrp传入的函数参数
            this->HandlerHttpRquest(sock, client);
        });
    }
    ~Http()
    {
    }
private:
    std::unique_ptr<TcpServer> tsvrp;
};